!pip install -U git+https://github.com/albumentations-team/albumentations
import torch
import random
import pandas as pd
import numpy as np
from torch.utils.data import DataLoader, Dataset
import math
import sys
import skimage.io
import os
import json
import seaborn as sns
import tensorboard
import time
import albumentations as A
from torch.utils.tensorboard import SummaryWriter
from albumentations.pytorch.transforms import ToTensor
import torchvision
import imageio
import cv2 as cv
from matplotlib import pyplot as plt
%cd /content/drive/My Drive/Foodvisor/challenge
img_names = os.listdir('assignment_imgs')
img_annotations = open('img_annotations.json')
img_annotations = json.load(img_annotations)
info_df = pd.read_csv('label_mapping.csv')
#example
for k in range(3):
imgex = img_names[k]
image = skimage.io.imread('assignment_imgs/'+imgex)/255
print('image size is ',np.shape(image))
fig = plt.figure(figsize=(10,10))
plt.imshow(image)
nb_windows = len(img_annotations[imgex])
color=plt.cm.rainbow(np.linspace(0,1,nb_windows))
labels = []
for i in range(nb_windows):
annot_dict = img_annotations[imgex][i]
bbox = annot_dict['box']
id = annot_dict['id']
x1 , y1, x2 , y2 = bbox[0], bbox[1], bbox[0]+bbox[2], bbox[1]+bbox[3]
print([x1,y1])
print([x2,y2])
plt.plot([x1, x1, x2, x2, x1], [y1, y2, y2, y1, y1], 'b-',color=color[i])
label = info_df.loc[info_df['labelling_id']==id]['labelling_name_fr'].item()
labels.append(label)
plt.legend(labels)
plt.show()
def create_df(info_df,img_annotations):
"""
Create df with useful informations for tomatoes allergy detection
"""
image_paths = []
labels = []
bboxs = []
is_tomates = []
nb_tomates = 0
nb_objects = 0
for key in img_annotations.keys():
image_path = key
image_paths.append(key)
nb_windows = len(img_annotations[key])
img_labels = []
img_bboxs = []
tomate_per_img = []
for k in range(nb_windows):
annot_dict = img_annotations[key][k]
if not annot_dict['is_background']:
bbox = annot_dict['box']
id = annot_dict['id']
fr_label = info_df.loc[info_df['labelling_id']==id]['labelling_name_fr'].item()
# The images are going to be downsampled by 2 for computational reasons
x1 , y1, h , w = bbox[0]//2, bbox[1]//2, bbox[2]//2-1, bbox[3]//2-1
# sometimes the bounding box is too big
h = min(h,299-y1)
w = min(w,299-x1)
# we use the coco bbox convention
img_bboxs.append([x1,y1,w,h])
img_labels.append(fr_label)
"""
if annot_dict['is_background']:
tomate_per_img.append(2)
"""
if 'Tomate' in fr_label or 'Raviolis sauce tomate' in fr_label:
tomate_per_img.append(1)
nb_tomates = nb_tomates + 1
else:
nb_objects = nb_objects + 1
tomate_per_img.append(0)
is_tomates.append(tomate_per_img)
labels.append(img_labels)
bboxs.append(img_bboxs)
data= {'image_path':image_paths,'label':labels,'bbox':bboxs,'is_tomato':is_tomates}
df= pd.DataFrame(data)
return df, nb_tomates , nb_objects
df , nb_tomates, nb_objects = create_df(info_df,img_annotations)
#Setting the weights for dealing with class imbalance
w_1 = nb_objects/nb_tomates
w_0 = 1
print("The weights of errors for tomatoe samples:",w_1 )
print('proportion of tomatoes ',100*(nb_tomates/(nb_objects+nb_tomates)))
class FoodDataset(Dataset):
"""Foodvisor tomatoe detection dataset."""
def __init__(self,image_dir,info_df ,input_size=(300,300), transform=None, weights=[w_0,w_1]):
"""
Args:
info_df (Dataframe): Dataframe of the image paths and annotations.
image_dir (string): Directory with all the images
transform (callable, optional): Optional transform to be applied
on a sample.
"""
self.info_df = info_df
self.image_dir = image_dir
self.input_size=input_size
self.transform = transform
self.weights = weights
def __len__(self):
return len(self.info_df)
def load_image(self, idx):
"""Generate an image from the specs of the given image ID.
"""
image_id = self.info_df.loc[idx, "image_path"]
img_name = os.path.join(self.image_dir,image_id)
image = skimage.io.imread(img_name)
return image
def __getitem__(self, idx):
if torch.is_tensor(idx):
idx = idx.tolist()
image_path = self.info_df.loc[idx, "image_path"]
img_name = os.path.join(self.image_dir,image_path)
image = skimage.io.imread(img_name)
labels = self.info_df.loc[idx, "is_tomato"]
bboxes = self.info_df.loc[idx, "bbox"]
resize_transform = A.Resize(self.input_size[0],self.input_size[1])(image=image)
image = resize_transform['image']
if self.transform:
data = {"image": image,"bboxes":bboxes,'class_labels':labels}
augmented = self.transform(**data)
image = augmented['image']
bboxes = augmented['bboxes']
labels = augmented['class_labels']
# Normalization and converting everything to Tensor
simple_transform = simple_preprocess()(image= image)
image = simple_transform['image']
bboxes = torch.as_tensor(bboxes, dtype=torch.float32)
labels = torch.as_tensor(labels, dtype=torch.int64)
image_id = torch.Tensor([idx])
# Use the COCO template for targets to be able to evaluate the model with COCO API
area = bboxes[:,2]*bboxes[:,3]
bboxes[:,2] = bboxes[:,0]+bboxes[:,2]
bboxes[:,3] = bboxes[:,1] + bboxes[:,3]
target = {"boxes": bboxes,"labels": labels,"image_id": image_id,"area": area,"iscrowd": torch.as_tensor([0], dtype=torch.int64)}
return image, target, self.weights[1 in target['labels']]
mean = [0.485, 0.456, 0.406]
std = [0.229, 0.224, 0.225]
normalize = {'mean':mean,'std':std}
def complex_preprocess():
return A.Compose([A.HorizontalFlip(),
#A.RandomCrop(width=600, height=600,p=.9),
A.VerticalFlip(),
#A.Crop(x_min = 0, y_min = 0, x_max = 300, y_max = 300),
#A.CLAHE(clip_limit=4,p=0.3),
#A.ChannelDropout(p=0.2),
#A.HueSaturationValue(p=0.2),
#A.Posterize(p=0.2),
#A.RGBShift(50,50,50,p=0.3),
A.RandomGamma((40,120)),
A.GaussNoise(p=0.3),
A.Blur(blur_limit = 8,p=0.3),
A.RandomContrast((-0.4,0.4))], bbox_params=A.BboxParams(format='coco',label_fields=['class_labels']))
def simple_preprocess():
return A.Compose([ToTensor()
])
#normalize=normalize
def to_numpy(x):
if not (isinstance(x, np.ndarray) or x is None):
if x.is_cuda:
x = x.data.cpu()
x = x.numpy()
return x
def unnormalize(img,mean = mean, std = std,image_size=(300,300,3)):
"Unnormalize a given image tensor and make it plotable"
img= img.permute(1, 2, 0)
# plt imshow only accept positive values
unnormalized_img = torch.tensor(np.ones(image_size))
for c in range(3):
unnormalized_img[:,:,c] = std[c]*img[:,:,c] +mean[c]
return to_numpy(unnormalized_img)
img_dir = 'assignment_imgs'
dataset = FoodDataset(image_dir = img_dir ,info_df = df ,input_size=(300,300,3), transform=None)
# Augmentation vizualisation NB: Mettre conventions de coco
for i in range(20):
fig = plt.Figure(figsize=(20,20))
img, target,weights = dataset.__getitem__(i)
print(weights)
bboxes = target['boxes']
unnormalized_img = unnormalize(img,mean = (0,0,0),std = (1,1,1))
plt.imshow(to_numpy(unnormalized_img))
nb_window = len(bboxes)
print(target['labels'])
for k in range(nb_window):
bbox = bboxes[k]
x1 , y1, x2 , y2 = bbox[0], bbox[1], bbox[2], bbox[3]
plt.plot([x1, x1, x2, x2, x1], [y1, y2, y2, y1, y1], 'b-')
plt.show()
#splitting into train, valid and test
from sklearn.model_selection import train_test_split
train_val_df, test_df = train_test_split(df, test_size=0.1, random_state=42, shuffle=True)
train_df , val_df = train_test_split(train_val_df, test_size=0.2, random_state=42, shuffle=True)
train_df = train_df.reset_index()
val_df = val_df.reset_index()
test_df = test_df.reset_index()
from collections import defaultdict, deque
import datetime
import pickle
import time
import torch
import torch.distributed as dist
import errno
import os
class SmoothedValue(object):
"""Track a series of values and provide access to smoothed values over a
window or the global series average.
"""
def __init__(self, window_size=20, fmt=None):
if fmt is None:
fmt = "{median:.4f} ({global_avg:.4f})"
self.deque = deque(maxlen=window_size)
self.total = 0.0
self.count = 0
self.fmt = fmt
def update(self, value, n=1):
self.deque.append(value)
self.count += n
self.total += value * n
def synchronize_between_processes(self):
"""
Warning: does not synchronize the deque!
"""
if not is_dist_avail_and_initialized():
return
t = torch.tensor([self.count, self.total], dtype=torch.float64, device='cuda')
dist.barrier()
dist.all_reduce(t)
t = t.tolist()
self.count = int(t[0])
self.total = t[1]
@property
def median(self):
d = torch.tensor(list(self.deque))
return d.median().item()
@property
def avg(self):
d = torch.tensor(list(self.deque), dtype=torch.float32)
return d.mean().item()
@property
def global_avg(self):
return self.total / self.count
@property
def max(self):
return max(self.deque)
@property
def value(self):
return self.deque[-1]
def __str__(self):
return self.fmt.format(
median=self.median,
avg=self.avg,
global_avg=self.global_avg,
max=self.max,
value=self.value)
def all_gather(data):
"""
Run all_gather on arbitrary picklable data (not necessarily tensors)
Args:
data: any picklable object
Returns:
list[data]: list of data gathered from each rank
"""
world_size = get_world_size()
if world_size == 1:
return [data]
# serialized to a Tensor
buffer = pickle.dumps(data)
storage = torch.ByteStorage.from_buffer(buffer)
tensor = torch.ByteTensor(storage).to("cuda")
# obtain Tensor size of each rank
local_size = torch.tensor([tensor.numel()], device="cuda")
size_list = [torch.tensor([0], device="cuda") for _ in range(world_size)]
dist.all_gather(size_list, local_size)
size_list = [int(size.item()) for size in size_list]
max_size = max(size_list)
# receiving Tensor from all ranks
# we pad the tensor because torch all_gather does not support
# gathering tensors of different shapes
tensor_list = []
for _ in size_list:
tensor_list.append(torch.empty((max_size,), dtype=torch.uint8, device="cuda"))
if local_size != max_size:
padding = torch.empty(size=(max_size - local_size,), dtype=torch.uint8, device="cuda")
tensor = torch.cat((tensor, padding), dim=0)
dist.all_gather(tensor_list, tensor)
data_list = []
for size, tensor in zip(size_list, tensor_list):
buffer = tensor.cpu().numpy().tobytes()[:size]
data_list.append(pickle.loads(buffer))
return data_list
def reduce_dict(input_dict, average=True):
"""
Args:
input_dict (dict): all the values will be reduced
average (bool): whether to do average or sum
Reduce the values in the dictionary from all processes so that all processes
have the averaged results. Returns a dict with the same fields as
input_dict, after reduction.
"""
world_size = get_world_size()
if world_size < 2:
return input_dict
with torch.no_grad():
names = []
values = []
# sort the keys so that they are consistent across processes
for k in sorted(input_dict.keys()):
names.append(k)
values.append(input_dict[k])
values = torch.stack(values, dim=0)
dist.all_reduce(values)
if average:
values /= world_size
reduced_dict = {k: v for k, v in zip(names, values)}
return reduced_dict
class MetricLogger(object):
def __init__(self, delimiter="\t"):
self.meters = defaultdict(SmoothedValue)
self.delimiter = delimiter
def update(self, **kwargs):
for k, v in kwargs.items():
if isinstance(v, torch.Tensor):
v = v.item()
assert isinstance(v, (float, int))
self.meters[k].update(v)
def __getattr__(self, attr):
if attr in self.meters:
return self.meters[attr]
if attr in self.__dict__:
return self.__dict__[attr]
raise AttributeError("'{}' object has no attribute '{}'".format(
type(self).__name__, attr))
def __str__(self):
loss_str = []
for name, meter in self.meters.items():
loss_str.append(
"{}: {}".format(name, str(meter))
)
return self.delimiter.join(loss_str)
def synchronize_between_processes(self):
for meter in self.meters.values():
meter.synchronize_between_processes()
def add_meter(self, name, meter):
self.meters[name] = meter
def log_every(self, iterable, print_freq, header=None):
i = 0
if not header:
header = ''
start_time = time.time()
end = time.time()
iter_time = SmoothedValue(fmt='{avg:.4f}')
data_time = SmoothedValue(fmt='{avg:.4f}')
space_fmt = ':' + str(len(str(len(iterable)))) + 'd'
if torch.cuda.is_available():
log_msg = self.delimiter.join([
header,
'[{0' + space_fmt + '}/{1}]',
'eta: {eta}',
'{meters}',
'time: {time}',
'data: {data}',
'max mem: {memory:.0f}'
])
else:
log_msg = self.delimiter.join([
header,
'[{0' + space_fmt + '}/{1}]',
'eta: {eta}',
'{meters}',
'time: {time}',
'data: {data}'
])
MB = 1024.0 * 1024.0
for obj in iterable:
data_time.update(time.time() - end)
yield obj
iter_time.update(time.time() - end)
if i % print_freq == 0 or i == len(iterable) - 1:
eta_seconds = iter_time.global_avg * (len(iterable) - i)
eta_string = str(datetime.timedelta(seconds=int(eta_seconds)))
if torch.cuda.is_available():
print(log_msg.format(
i, len(iterable), eta=eta_string,
meters=str(self),
time=str(iter_time), data=str(data_time),
memory=torch.cuda.max_memory_allocated() / MB))
else:
print(log_msg.format(
i, len(iterable), eta=eta_string,
meters=str(self),
time=str(iter_time), data=str(data_time)))
i += 1
end = time.time()
total_time = time.time() - start_time
total_time_str = str(datetime.timedelta(seconds=int(total_time)))
print('{} Total time: {} ({:.4f} s / it)'.format(
header, total_time_str, total_time / len(iterable)))
def collate_fn(batch):
return tuple(zip(*batch))
def warmup_lr_scheduler(optimizer, warmup_iters, warmup_factor):
def f(x):
if x >= warmup_iters:
return 1
alpha = float(x) / warmup_iters
return warmup_factor * (1 - alpha) + alpha
return torch.optim.lr_scheduler.LambdaLR(optimizer, f)
def mkdir(path):
try:
os.makedirs(path)
except OSError as e:
if e.errno != errno.EEXIST:
raise
def setup_for_distributed(is_master):
"""
This function disables printing when not in master process
"""
import builtins as __builtin__
builtin_print = __builtin__.print
def print(*args, **kwargs):
force = kwargs.pop('force', False)
if is_master or force:
builtin_print(*args, **kwargs)
__builtin__.print = print
def is_dist_avail_and_initialized():
if not dist.is_available():
return False
if not dist.is_initialized():
return False
return True
def get_world_size():
if not is_dist_avail_and_initialized():
return 1
return dist.get_world_size()
def get_rank():
if not is_dist_avail_and_initialized():
return 0
return dist.get_rank()
def is_main_process():
return get_rank() == 0
def save_on_master(*args, **kwargs):
if is_main_process():
torch.save(*args, **kwargs)
def init_distributed_mode(args):
if 'RANK' in os.environ and 'WORLD_SIZE' in os.environ:
args.rank = int(os.environ["RANK"])
args.world_size = int(os.environ['WORLD_SIZE'])
args.gpu = int(os.environ['LOCAL_RANK'])
elif 'SLURM_PROCID' in os.environ:
args.rank = int(os.environ['SLURM_PROCID'])
args.gpu = args.rank % torch.cuda.device_count()
else:
print('Not using distributed mode')
args.distributed = False
return
args.distributed = True
torch.cuda.set_device(args.gpu)
args.dist_backend = 'nccl'
print('| distributed init (rank {}): {}'.format(
args.rank, args.dist_url), flush=True)
torch.distributed.init_process_group(backend=args.dist_backend, init_method=args.dist_url,
world_size=args.world_size, rank=args.rank)
torch.distributed.barrier()
setup_for_distributed(args.rank == 0)
def accuracy(gt_labels, pred_labels):
return len(np.where(gt_labels == pred_labels)[0])/len(gt_labels)
from sklearn.metrics import roc_auc_score,f1_score, recall_score, precision_score, confusion_matrix
def compute_metrics(true_label,pred_label):
recall = recall_score(true_label,pred_label)
precision = precision_score(true_label,pred_label)
f1_score = 2 * (precision * recall) / (precision + recall)
tn, fp, fn, tp = confusion_matrix(true_label, pred_label).ravel()
sensitivity = tp / (tp + fn)
specificity = tn / (tn + fp)
return {'recall':recall,'precision':precision,'f1':f1_score,'sensitivity':sensitivity,'specificity':specificity}
def IoU(boxA, boxB):
# determine the (x, y)-coordinates of the intersection rectangle
xA1, yA1, xA2, yA2 = boxA
xB1, yB1, xB2, yB2 = boxB
x1 = max(xA1, xB1)
y1 = max(yA1, yB1)
x2 = min(xA2, xB2)
y2 = min(yA2, yB2)
# compute the area of intersection rectangle
intersection = max(0, x2 - x1 + 1) * max(0, y2 - y1 + 1)
# compute the area of both the prediction and ground-truth
# rectangles
boxAArea = (xA2 - xA1 + 1) * (yA2 - yA1 + 1)
boxBArea = (xB2 - xB1 + 1) * (yB2 - yB1 + 1)
union = boxAArea + boxBArea - intersection
return intersection / union
def train_one_epoch(model, optimizer,criterion,weights, data_loader, device, epoch, print_freq):
model.train()
metric_logger = MetricLogger(delimiter=" ")
metric_logger.add_meter('lr', SmoothedValue(window_size=1, fmt='{value:.6f}'))
header = 'Epoch: [{}]'.format(epoch)
for i, values in enumerate(metric_logger.log_every(data_loader, print_freq, header)):
images, targets, weights = values
images = list(image.to(device) for image in images)
targets = [{k: v.to(device) for k, v in t.items()} for t in targets]
weights = torch.Tensor(weights).to(device)
# Feed the training samples to the model and compute the losses
loss_dict = model(images, targets)
loss_dict['loss_classifier'] = 10*loss_dict['loss_classifier']
losses = sum(loss for loss in loss_dict.values())
# reduce losses over all GPUs for logging purposes
loss_dict_reduced = reduce_dict(loss_dict)
losses_reduced = sum(loss for loss in loss_dict_reduced.values())
loss_value = losses_reduced.item()
if not math.isfinite(loss_value):
print("Loss is {}, stopping training".format(loss_value))
print(loss_dict_reduced)
sys.exit(1)
# Pytorch function to initialize optimizer
optimizer.zero_grad()
# Compute gradients or the backpropagation
losses.backward()
# Update current gradient
optimizer.step()
metric_logger.update(loss=losses_reduced, **loss_dict_reduced)
metric_logger.update(lr=optimizer.param_groups[0]["lr"])
# Record losses to plot learning curves
if i == 0:
history = {key: val.cpu().detach() for key, val in loss_dict_reduced.items()}
history['loss'] = losses_reduced.cpu().detach()
else:
for key, val in loss_dict_reduced.items():history[key] += val.cpu().detach()
history['loss'] += losses_reduced.cpu().detach()
return history
if torch.cuda.is_available():
device='cuda'
else:
device = 'cpu'
def validate_one_epoch(model, data_loader, device=device, print_freq=100):
model.train()
metric_logger = MetricLogger(delimiter=" ")
header = "Validation: "
for i, values in enumerate(metric_logger.log_every(data_loader, print_freq, header)):
images, targets, weights = values
images = list(image.to(device) for image in images)
targets = [{k: v.to(device) for k, v in t.items()} for t in targets]
loss_dict = model(images, targets)
losses = sum(loss for loss in loss_dict.values())
# reduce losses over all GPUs for logging purposes
loss_dict_reduced = reduce_dict(loss_dict)
losses_reduced = sum(loss for loss in loss_dict_reduced.values())
loss_value = losses_reduced.item()
metric_logger.update(loss=losses_reduced, **loss_dict_reduced)
# Record losses to plot learning curves
if i == 0:
history = {key: val.cpu().detach() for key, val in loss_dict_reduced.items()}
history['loss'] = losses_reduced.cpu().detach()
else:
for key, val in loss_dict_reduced.items():history[key] += val.cpu().detach()
history['loss'] += losses_reduced.cpu().detach()
return history
def evaluate(model, loader, device,batch_size):
model.eval()
gt_labels, pred_labels = [], []
gt_boxes, pred_boxes = np.empty(4), np.empty(4)
for i, sample in enumerate(loader, 1):
images, targets, weights = sample
images = list(img.to(device) for img in images)
targets = [{k: v.to(device) for k, v in t.items()} for t in targets]
with torch.no_grad():
prediction = model(images)
for k in range(batch_size):
istomate_target = 1 in to_numpy(targets[k]['labels'])
istomate_pred = 1 in to_numpy(prediction[k]['labels'])
gt_labels.append(int(istomate_target))
pred_labels.append(int(istomate_pred))
if len(to_numpy(prediction[k]['boxes']))>0:
gt_boxes = np.vstack((gt_boxes, target['boxes'][k]))
pred_boxes = np.vstack((pred_boxes, prediction[k]['boxes'][0].cpu()))
gt_boxes = np.array(gt_boxes)
pred_boxes = np.array(pred_boxes)
pred_labels = np.array(pred_labels)
gt_labels = np.array(gt_labels)
d = compute_metrics(gt_labels, pred_labels)
print("classification metric over validation set:",d)
average_iou = np.mean([IoU(gt_boxes[i], pred_boxes[i]) for i in range(len(gt_boxes))])
print("Average IoU over {} set: {:.2f}".format('validation data', average_iou))
acc = accuracy(gt_labels, pred_labels)
print('Accuracy over {} set: {:.3f}'.format('validation_data', acc))
return d, average_iou, acc
import torchvision
from torchvision.models.detection.faster_rcnn import FastRCNNPredictor
# load a model pre-trained pre-trained on COCO
model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=False)
# replace the classifier with a new one, that has num_classes which is user-defined
num_classes = 2 # 2 classes (tomatoe or no tomatoes )
# get number of input channels for the classifier
in_features = model.roi_heads.box_predictor.cls_score.in_features
# replace the pre-trained head with a new one
model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)
def count_params(model):
"""Count the number of parameters"""
param_count = np.sum([torch.numel(p) for p in model.parameters()])
return param_count
print('Total parameters of Faster RCNN: ',count_params(model))
# our dataset has 3 classes
num_classes = 2
# move model to the right device
model.to(device)
# construct an optimizer
params = [p for p in model.parameters() if p.requires_grad]
optimizer = torch.optim.SGD(params, lr=0.0001,
momentum=0.9, weight_decay=0.00005)
lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer,
step_size=5,
gamma=0.5)
criterion = torch.nn.BCELoss()
weights = [w_0,w_1]
batch_size = 4
#Creating datasets from dataframes
train_dataset = FoodDataset(image_dir = img_dir ,info_df = train_df ,input_size=(300,300), transform=complex_preprocess())
val_dataset = FoodDataset(image_dir = img_dir ,info_df = val_df ,input_size=(300,300), transform=None)
#Creating DataLoaders
train_loader = torch.utils.data.DataLoader(train_dataset,
batch_size=batch_size, shuffle=True,sampler=None,
collate_fn=collate_fn,drop_last=True)
val_loader = torch.utils.data.DataLoader(val_dataset,
batch_size=batch_size, shuffle=True,sampler=None,
collate_fn=collate_fn,drop_last=True)
num_epochs = 50
save_frequency = 1
for epoch in range(num_epochs):
# Train for one epoch, printing every 10 iterations
train_his_ = train_one_epoch(model, optimizer,criterion,weights, train_loader, device, epoch, print_freq=100)
# Compute losses over the validation set
with torch.no_grad():
val_his_ = validate_one_epoch(model, val_loader, device, print_freq=100)
d, average_iou, acc = evaluate(model,val_loader,device, batch_size)
val_his_['f1'] = d['f1']
val_his_['average_iou'] = average_iou
val_his_['acc'] = acc
# Update the learning rate
lr_scheduler.step()
# Store loss values to plot learning curves afterwork.
if epoch == 0:
train_history = {k: [v] for k, v in train_his_.items()}
val_history = {k: [v] for k, v in val_his_.items()}
else:
for k, v in train_his_.items():train_history[k] += [v]
for k, v in val_his_.items():val_history[k] += [v]
# Save the model
if epoch % save_frequency==0:
session_name = 'Test_session' + '_' + time.strftime('%m.%d %Hh%M')
save_path = "/content/drive/My Drive/Foodvisor/challenge/model_zoo/"
model_path = save_path + session_name + '_'+ 'Epoch'+ str(epoch)+ '_model.pth.tar'
torch.save(model, model_path)
torch.cuda.empty_cache()
for k in train_history:
""" FILL HERE """
plt.plot(np.arange(len(train_history[k]), dtype=int), train_history[k]/np.max(train_history[k]), label='Train')
plt.plot(np.arange(len(val_history[k]), dtype=int), val_history[k]/np.max(val_history[k]), label='Validation')
plt.title(k)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.show()
test_dataset = FoodDataset(image_dir = img_dir,info_df=test_df)
#retrieve model
PATH = '/content/drive/My Drive/Foodvisor/challenge/model_zoo/Test_session_10.09 14h37_Epoch1_model.pth.tar'
model = torch.load(PATH)
model.to(device)
test_loader = torch.utils.data.DataLoader(test_dataset,
batch_size=1, shuffle=True,sampler=None,
collate_fn=collate_fn,drop_last=True)
def has_tomatoes(img_path, model, nms_thres=0.001,device='cuda'):
model.to(device)
model.eval()
image = skimage.io.imread(img_path)
resize_transform = A.Resize(300,300)(image=image)
image = resize_transform['image']
simple_transform = simple_preprocess()(image= image)
image = simple_transform['image']
image = image.unsqueeze(0)
with torch.no_grad():
prediction = model(image.to(device))
boxes = to_numpy(prediction[0]['boxes'])
scores = to_numpy(prediction[0]['scores'])
#kept_boxes = non_max_suppression(boxes, scores, nms_thres)
pred_label = to_numpy(prediction[0]["labels"])#[kept_boxes]
return 1 in pred_label
for img_path in img_names[80:90]:
start = time.time()
fig = plt.figure(figsize=(5,5))
img_path = os.path.join('assignment_imgs',img_path)
b = has_tomatoes(img_path,model)
end = time.time()
print('prediction done in',end-start)
print('is there a tomatoe?',b)
plt.imshow(skimage.io.imread(img_path))
plt.show()
start = time.time()
evaluate(model,test_loader,'cuda',1)
end = time.time()
print('time per prediction:',(end-start)/len(test_df))
!pip install nbconvert
%cd /content/drive/My Drive/Colab Notebooks/
!jupyter nbconvert --to html Foodvisor_challenge.ipynb